package world.square;

import static org.junit.Assert.*;

import java.math.BigDecimal;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import world.edges.Border;
import world.edges.Wall;
import world.placement.Direction;

public class SquareTest {
	private static Square standardSquare;
	private static Square borderedSquare;
	/**
	 * Create some immutable squares
	 * 
	 * @post   the variable standardSquare references to a new square,
	 * 			with a temperature of 25 degrees celcius and humidity of 10%
	 * @post   the variable hotSquare references to a new square,
	 * 			with a temperature of 55 degrees celcius and humidity of 20%
	 * @post   the variable coldSquare references to a new square,
	 * 			with a temperature of -63 degrees celcius and humidity of 20%
	 * @post   the variable humidSquare references to a new square,
	 * 			with a temperature of 25 degrees celcius and humidity of 63%
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		standardSquare = new Square();
		borderedSquare = new Square(Direction.NORTH,Direction.EAST,Direction.SOUTH,Direction.WEST,Direction.FLOOR,Direction.CEILING);

		hotSquare= new Square(new Temperature(55,TemperatureScale.CELCIUS),new BigDecimal("20"), Direction.NORTH);
		coldSquare= new Square(new Temperature(-63,TemperatureScale.CELCIUS),new BigDecimal("20"), Direction.NORTH);
		humidSquare = new Square(new Temperature(25,TemperatureScale.CELCIUS),new BigDecimal("63"), Direction.NORTH);
	}
	
	private static Square hotSquare;
	private static Square coldSquare;
	private static Square humidSquare;
	/**
	 * Create mutable squares
	 * 
	 * @post the variable testSquare1 references to a new square,
	 * 			with a temperature of 100 degrees celcius and humidity of 100%
	 * @post   the variable testSquare2 references to a new square,
	 * 			with a temperature of 25 degrees celcius and humidity of 10%
	 */
	@Before
	public void setUp() throws Exception { 
		testSquare1 = new Square (new Temperature(100,TemperatureScale.CELCIUS), new BigDecimal("100"), Direction.EAST);
		testSquare2 = new Square();

	}
	private static Square testSquare1; 
	private static Square testSquare2; 

	
	@Test
	public final void defaultConstructor_SingleCase() {
		Square newSquare = new Square(new Temperature(50,TemperatureScale.CELCIUS),new BigDecimal("45.64"), Direction.EAST); 
		assertEquals(new Temperature(50,TemperatureScale.CELCIUS), newSquare.getTemperature());
		assertEquals(new BigDecimal("45.64"), newSquare.getHumidity());
	}
	
	@Test
	public final void canHaveAsTemperature_TrueCase(){
		assertTrue(standardSquare.canHaveAsTemperature(new Temperature(25, TemperatureScale.CELCIUS)));
	}
	
	@Test
	public final void isValidTemperature_FalseCase(){
		assertFalse(standardSquare.canHaveAsTemperature(new Temperature(-300, TemperatureScale.CELCIUS)));
	}
	
	@Test
	public final void isValidHumidity_TrueCase(){
		
		assertTrue(Square.isValidHumidity(new BigDecimal("100.00")));
	}
	
	@Test
	public final void isValidHumidity_FalseCase(){
		assertFalse(Square.isValidHumidity(new BigDecimal("-1")));
	}
	
	@Test
	public final void getHeatDamage_SingleCase(){
		assertEquals(1,hotSquare.getHeatDamage());
	}
	
	@Test
	public final void getColdDamage_SingleCase(){
		assertEquals(5,coldSquare.getColdDamage());
	}
	
	@Test
	public final void getRustDamage_SingleCase(){
		assertEquals(4,humidSquare.getRustDamage());
	}
	
	@Test
	public final void isValidSpan_TrueCase(){
		assertTrue(standardSquare.isValidSpan(15, new BigDecimal("400")));
	}
	
	@Test
	public final void isValidSpan_FalseCase(){
		assertFalse(standardSquare.isValidSpan(50, new BigDecimal("40")));
	}
	
	@Test
	public final void getHasSlipperyFloor_TrueCase(){
		standardSquare.setHasSlipperyFloor(true);
		assertTrue (standardSquare.getHasSlipperyFloor());
	}
	@Test
	public final void getHasSlipperyFloor_FalseCase(){
		standardSquare.setHasSlipperyFloor(false);
		assertFalse (standardSquare.getHasSlipperyFloor());
	}
	
	@Test
	public final void isSlippery_TrueCases(){
		Square square = new Square();
		square.setHasSlipperyFloor (true);
		assertTrue (square.isSlippery());
		
		Square square1 = new Square();
		
		square1.setHumidity(new BigDecimal ("100.00"));
		assertTrue (square1.isSlippery());
		
		Square square2 = new Square();
		square2.setHumidity(new BigDecimal ("20"));
		square2.setTemperature(new Temperature(-20,TemperatureScale.CELCIUS));
		assertTrue (square2.isSlippery());
	}
	
	@Test
	public final void isSlippery_FalseCase(){
		Square square = new Square();
		assertFalse (square.isSlippery());
	}
	
	@Test
	public final void inhabitability_SingleCases(){
		standardSquare.setHumidity(new BigDecimal ("0"));
		standardSquare.setTemperature(new Temperature(100,TemperatureScale.CELCIUS));
		assertEquals (-0.80,standardSquare.inhabitability().doubleValue(),0.1E-10);
		
		standardSquare.setHumidity(new BigDecimal ("0"));
		standardSquare.setTemperature(new Temperature(-100,TemperatureScale.CELCIUS));
		assertEquals (-3,standardSquare.inhabitability().doubleValue(),0.1E-10);
		
		standardSquare.setHumidity(new BigDecimal ("100"));
		standardSquare.setTemperature(new Temperature(0,TemperatureScale.CELCIUS));
		assertEquals (0,standardSquare.inhabitability().doubleValue(),0.1E-10);
	}
	
	@Test
	public final void isBorderedInDirection_Truecases(){
		standardSquare.addBorders(new Border(new Wall(false),Direction.NORTH), new Border(new Wall(false),Direction.FLOOR));
		
		assertTrue(standardSquare.isBorderedInDirection(Direction.NORTH));
		assertTrue(standardSquare.isBorderedInDirection(Direction.FLOOR));

	}
	
	@Test
	public final void canHaveAsBorder_SingleCase(){
		assertTrue(standardSquare.canHaveAsBorder(new Border(new Wall(false),Direction.NORTH)));
	}
	
	@Test
	public final void removeBorders_SingleCase(){
		borderedSquare.removeBorders(Direction.FLOOR,Direction.EAST);
		assertFalse(borderedSquare.isBorderedInDirection(Direction.FLOOR));
		assertFalse(borderedSquare.isBorderedInDirection(Direction.EAST));
		assertTrue(borderedSquare.isBorderedInDirection(Direction.WEST));

	}
	
	
	
	@Test
	public final void mergeWith_SingleCases() throws Exception{
		setUp();
		
		testSquare1.mergeWith(testSquare2, Direction.NORTH);	
		
		assertEquals (86.87, testSquare1.getTemperature().getValue().doubleValue(),0.1E-10);
		assertEquals (86.87, testSquare2.getTemperature().getValue().doubleValue(),0.1E-10);
		
		assertEquals (55.00, testSquare1.getHumidity().doubleValue(),0.1E-10);
		assertEquals (55.00, testSquare2.getHumidity().doubleValue(),0.1E-10);
	}
	
	@Test
	public final void calculateWeights() throws Exception{
		setUp();

		assertEquals (1.65,testSquare1.calculateWeight(testSquare2.getHumidity(), testSquare1.getHumidity()).doubleValue(),0.1E-10);
		assertEquals (0.35,testSquare1.calculateWeight(testSquare1.getHumidity(), testSquare2.getHumidity()).doubleValue(),0.1E-10);

		testSquare1.setTemperature(new Temperature(57,TemperatureScale.CELCIUS));
		testSquare1.setHumidity(new BigDecimal ("0"));
		testSquare2.setTemperature(new Temperature(57,TemperatureScale.CELCIUS));
		testSquare2.setHumidity(new BigDecimal("1"));
		
		assertEquals (0.20,testSquare1.calculateWeight(testSquare2.getHumidity(), testSquare1.getHumidity()).doubleValue(),0.1E-10);
		assertEquals (1.80,testSquare1.calculateWeight(testSquare1.getHumidity(), testSquare2.getHumidity()).doubleValue(),0.1E-10);

		testSquare2.setHumidity(new BigDecimal("0"));
		assertEquals (1,testSquare1.calculateWeight(testSquare2.getHumidity(), testSquare1.getHumidity()).doubleValue(),0.1E-10);
		assertEquals (1,testSquare1.calculateWeight(testSquare1.getHumidity(), testSquare2.getHumidity()).doubleValue(),0.1E-10);
		
		setUp();
		Square.setConstantWeightedMean(new BigDecimal( "0.30"));
		
		assertEquals (1.57,testSquare1.calculateWeight(testSquare2.getHumidity(), testSquare1.getHumidity()).doubleValue(),0.1E-10);
		assertEquals (0.43,testSquare1.calculateWeight(testSquare1.getHumidity(), testSquare2.getHumidity()).doubleValue(),0.1E-10);
			
		Square.setConstantWeightedMean (new BigDecimal("0.20"));
	}
	
	
	@Test
	public final void isValidConstant_TrueCases (){
		assertTrue(Square.isValidConstant(new BigDecimal ("0.1")));
		assertTrue(Square.isValidConstant(new BigDecimal ("0.4")));
	}
	
	@Test
	public final void isValidConstant_FalseCases (){
		assertFalse(Square.isValidConstant(new BigDecimal ("0.09")));
		assertFalse(Square.isValidConstant(new BigDecimal ("0.41")));
	}
	
	@Test
	public final void calculateWeightedMean_SingleCases(){
		Square square1 = new Square (new Temperature(100,TemperatureScale.CELCIUS), new BigDecimal("100"), Direction.NORTH); //100, 100
		Square square2 = new Square();
		assertEquals (86.87,square1.calculateWeightedMean(square1.getTemperature().getValue(), square2.getTemperature().getValue(), square1.getHumidity(), square2.getHumidity()).doubleValue(), 0.1E-10);
		
		Square square3 = new Square (new Temperature(20,TemperatureScale.CELCIUS), new BigDecimal("0"), Direction.NORTH); 
		Square square4 = new Square (new Temperature(85,TemperatureScale.CELCIUS), new BigDecimal("10.0012"), Direction.NORTH); 
		assertEquals (78.5,square3.calculateWeightedMean(square3.getTemperature().getValue(), square4.getTemperature().getValue(), square3.getHumidity(), square4.getHumidity()).doubleValue(), 0.1E-10);
	}
	
	@Test
	public final void calculateAverage_SingleCases(){
		assertEquals(50,standardSquare.calculateAverage(new BigDecimal ("100"), new BigDecimal("0")).doubleValue(),0.1E-10);
		assertEquals(-30,standardSquare.calculateAverage(new BigDecimal ("-50"), new BigDecimal("-10")).doubleValue(),0.1E-10);
		assertEquals(113.5,standardSquare.calculateAverage(new BigDecimal ("113"), new BigDecimal("114")).doubleValue(),0.1E-10);
	}
	
	@Test
	public final void getConstantWeightedMean_SingleCases(){
		assertEquals (0.2, standardSquare.getConstantWeightedMean().doubleValue(),0.1E-10 );
		Square.setConstantWeightedMean(new BigDecimal ("0.4"));
		assertEquals (0.4, standardSquare.getConstantWeightedMean().doubleValue(),0.1E-10 );
		
	}
	
	
}
